package main

import "fmt"

// 是一种特殊的结构：闭包结构，违反了程序正常的生命周期。合法的使用。程序允许的一种特殊结构，变量作用域升级了。

// 什么时候用闭包： js （xxxxxxx.html   引用大量的第三方库：10个js库，js库中很多变量名是冲突的）
// js 很多框架都是闭包结构的，防止变量冲突，全局变量污染

// 我的代码里面的变量就不会和你代码里面的变量冲突了。解决一些变量作用域冲突的问题。

/*
闭包结构:
一个外层函数中，有内层函数，该内层函数中，会操作外层函数的局部变量并且该外层函数的返回值就是这个内层函数。

在闭包结构中：局部变量的生命周期就会发生改变，
正常的局部变量会随着函数的调用而创建，随着函数的结束而销毁
但是闭包结构中的外层函数的局部变量并不会随着外层函数的结束而销毁，因为内层函数还在继续使用.

// 由于垃圾回收期不会将闭包中的变量销毁，可能会造成内存泄漏。
*/

// 高级项目中遇到的问题：
// 你的代码变量和你同事的变量冲突了，解决。 i 新建一个变量。 第三方库中的代码都是闭包结构实现的导出。
var i int = 10

func main() {
	r1 := increment()
	fmt.Println(r1) // 返回的是一个 increment() 内存函数，还没有执行
	// -- 执行这个内层函数
	//闭包实例；
	v1 := r1()
	fmt.Println(v1)
	//新的闭包实例；
	v2 := r1()
	fmt.Println(v2)
	fmt.Println(r1())
	fmt.Println(r1())
	fmt.Println(r1())
	// 你写的代码是对的，但是结果不对，你的变量被污染了
	fmt.Println("--------------------------")

	// r2和r1指向同一个地址,调用的是同一个函数
	r2 := increment() // 再次调用的时候 ，i = 0
	v3 := r2()
	fmt.Println(v3) // 1

	//因为我们内层还是用i，还存在引用，系统不会销货这个i，保护，单独作用r1
	fmt.Println(r1()) // 6
	// 关于r1() 中的这里的i 并没有随着 第二次创建就被销毁归0，而是在内层函数继续调用着。
	fmt.Println(r2()) // 2
	// r1 名字 ----> 内存地址 &r1
	fmt.Printf("%p\n", &r1)
	fmt.Printf("%p\n", &r2)

	//只不过就是第二次调用的函数的外部就会被销毁，但是内部函数的变量依旧存在
}

// 自增函数
// increment() 函数返回值为  func() int 类型
func increment() func() int { // 外层函数，项目（很多的全局变量）
	// 定义一个局部变量
	i := 0
	// 在外层函数内部定义一个匿名函数，给变量自增并返回。因为我们内层还是用i，还存在引用，系统不会销毁这个i，保护单独作用域
	fun := func() int {
		i++
		return i
	}
	return fun
}

//总结：调用多个闭包函数的实例，每个实例变量都不受影响，相互独立（每次变化，都是按自己实例的变量进行变化）
//	多次调用同一个函数闭包的实例，变量会自己变化
